package br.edu.utfpr.bsi.si.team;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import br.edu.utfpr.bsi.si.Config;
import br.edu.utfpr.bsi.si.fuzzy.Fuzzy;
import br.edu.utfpr.bsi.si.team.jogadores.Robo;
import robocode.rescue.RobotInfo;
import robocode.rescue.interfaces.RMIRobotInterface;
import jason.RoborescueEnv;
import jason.asSyntax.Structure;

public class Ambiente extends RoborescueEnv {

	private final int numRobos = Config.numRobos;

	public Robo[] robos;
	public Robo[] robosInimigos;
	public Robo refem;
	public Robo prisioneiro;

	private RobotInfo[] robosRaw;
	private RobotInfo[] robosInimigosRaw;
	private RMIRobotInterface[] teamRef;
	
	public static void main(String[] args) {
		Ambiente team = new Ambiente();
		team.init(new String[] { "Sample", "localhost" });
		team.setup();
		while (true) {
			try {
				team.mainLoop();
				Thread.sleep(20);
			} catch (RemoteException ex) {
				ex.printStackTrace();
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		}
	}

	@Override
	public void setup() {
		Robo.setAmbiente(this);
		robos = new Robo[Config.numRobos];
		robosInimigos = new Robo[Config.numRobos];
	}

	@Override
	public boolean executeAction(String ag, Structure action) {
		try {
			mainLoop();
			Thread.sleep(20);
		} catch (RemoteException ex) {
			ex.printStackTrace();
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}

		return true;
	}

	public void mainLoop() throws RemoteException {
		updateRobos();

		// chama o fuzzy
		Fuzzy f = new Fuzzy();
		int contD = 0;
		for (Robo robo : this.robos) {
			robo.funcao = f.getRobotFunction(robo);
			if (robo.funcao == 'D')
				contD++;
		}
//		this.robos[0].funcao = 'D';
//		this.robos[3].funcao = 'D';
		
		if ( contD > 2 ) {
			ArrayList<Robo> arrAux = new ArrayList<>();
			for (Robo robo : this.robos) {
				if (robo.funcao == 'D')
					arrAux.add(robo);
			}
			
			Collections.sort(arrAux, new Comparator<Robo>() {
	            public int compare(Robo c1, Robo c2) {
	                if (c1.distanciaRefem() > c2.distanciaRefem()) {
	                    return 1;
	                }
	                return -1;

	            }
	        });

			for (int i = 0; i < contD-2; i++) {
				this.robos[arrAux.get(i).num-1].funcao = 'A';	
			}
		}
		
		// determina quem eh o superjogador
//		for (Robo robo : this.robos) {
//			if (robo.funcao == 'A')
//				robo.superJogador = false;
//		}
//		this.robos[roboMaisProximoRefem()].superJogador = true;

		for (Robo robo : this.robos) {
			System.out.println("Robo " + robo.num + "=" + robo.funcao);
			robo.move();
		}
	}
	
	@Override
	public void end() {
		try {
			super.getEnvironmentInfraTier().getRuntimeServices().stopMAS();
		} catch (Exception ex) {
			ex.printStackTrace();
			System.exit(1);
		}
	}
	
	public void updateRobos() throws RemoteException {
		robosRaw = getServerRef().getMyTeamInfo(myTeam);
		robosInimigosRaw = getServerRef().getEnemyTeamInfo(myTeam);
		teamRef = getTeamRef();
		
		for (int i = 0; i < numRobos; i++) {
			if ( this.robos[i] == null)
				this.robos[i] = new Robo();
			
			this.robos[i].robo = robosRaw[i+1];
			this.robos[i].rinterface = teamRef[i+1];
			this.robos[i].num = i+1;

			if ( this.robosInimigos[i] == null)
				this.robosInimigos[i] = new Robo();
			
			this.robosInimigos[i].robo = robosInimigosRaw[i+1];
			this.robosInimigos[i].num = i+1;
		}
		
		if (refem == null)
			refem = new Robo();
		
		refem.robo = robosRaw[0];
		refem.rinterface= teamRef[0];
		
		if (prisioneiro == null)
			prisioneiro = new Robo();
		
		prisioneiro.robo = robosInimigosRaw[0];
		
	}
	
	public int roboMaisProximoRefem(){
		double distMin = 9999; 
		double dist;
		int num = 0;
		for (Robo robo : this.robos) {
			dist = robo.distanciaRefem();
			if ( dist < distMin ) {
				distMin = dist;
				num = robo.num-1;
			}
		}
		
		return num;
	}
	
	public double distanciaAdversarioMaisProximoRefem(){
		double distMin = 9999; 
		double dist;
		for (Robo inimigo : this.robosInimigos) {
			dist = inimigo.distanciaRefem();
			if ( dist < distMin ) {
				distMin = dist;
			}
		}
		
		return distMin;
	}
	
	public double distanciaAdversarioMaisProximoPrisioneiro(){
		double distMin = 9999; 
		double dist;
		for (Robo inimigo : this.robosInimigos) {
			dist = inimigo.distanciaPrisioneiro();
			if ( dist < distMin ) {
				distMin = dist;
			}
		}
		
		return distMin;
	}
}
